#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <sys/select.h>
#include <poll.h>

#include "Socket.hpp"
static const int gnum = 1024;
static const int TIMEOUT = 5000;

class PollServer
{

public:
    PollServer(int port)
        : _port(port), _sock(std::make_unique<sock::TcpSocket>("0.0.0.0", port))
    {
        _sock->CreateSocket();
        _sock->BindSocket();
        _sock->Listen();

        for(size_t i = 0; i < gnum; ++i)
        {
            _events[i].fd = -1; 
            _events[i].events = 0;
            _events[i].revents = 0;
        }
        _events[0].fd = _sock->GetSockfd();
        _events[0].events |= POLLIN;
    }

    ~PollServer()
    {
        _sock->Close();
    }

    void AcceptClient()
    {
        // listen 套接字就绪
        sockaddr_in clientAddr;
        socklen_t len = sizeof(clientAddr);
        int sockfd = _sock->Accept(&clientAddr, &len); // 这里调用accept不会阻塞，因为select已经监听到了有客户端连接
        if (sockfd < 0)
        {
            LOG(ERROR, "accept error...\n");
            return;
        }

        char ip[32];
        inet_ntop(AF_INET, &clientAddr.sin_addr, ip, sizeof(ip));

        LOG(INFO, "Get a new client, sockfd = %d, ClientInfo: %s:%d\n", sockfd, ip, ntohs(clientAddr.sin_port));

        // 将sockfd 添加进 poll
        int pos = 1;
        for(; pos < gnum; ++pos)
        {
            if(_events[pos].fd == -1)
            {
                _events[pos].fd = sockfd;
                _events[pos].events |= POLLIN;
                _events[pos].revents = 0;
                break;
            }
        }
        if(pos == gnum)
        {
            LOG(ERROR, "events 达到上限\n");
        }
        PrintDebug();
    }

    void Service(int i)
    {
        int sockfd = _events[i].fd;
        char buffer[1024];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        if(n > 0)
        {
            buffer[n] = '\0';
            std::string echo_str = "[server echo]# ";
            echo_str += buffer;

            send(sockfd, echo_str.c_str(), echo_str.size(), 0);
            LOG(INFO, "send: %s\n", echo_str.c_str());
        }
        else if(n == 0)
        {
            close(sockfd);
            _events[i].fd = -1;
            _events[i].events = 0;
            _events[i].revents = 0;

            // debug
            PrintDebug();
        }
        else 
        {
            LOG(ERROR, "read fail\n");
        }
    }

    void HandleEvent()
    {
        for(int i = 0; i < gnum; ++i)
        {
            if(_events[i].fd == -1) continue;
            
            int fd = _events[i].fd;
            short revents = _events[i].revents;

            // 读事件
            if(revents & POLLIN)
            {
                // 新链接到来
                if(fd == _sock->GetSockfd())
                    AcceptClient();
                else 
                {
                    // 读取数据
                    LOG(INFO, "处理读事件\n");
                    Service(i);
                }
            }

            // 写事件
            if(revents & POLLOUT)
            {
                // 写数据
                
            }
        }
    }

    void Loop()
    {
        while (true)
        {
            int n = poll(_events, gnum, TIMEOUT);
            if(n > 0)
            {
                LOG(INFO, "事件就绪\n");
                HandleEvent();
            }
            else if(n == 0)
            {
                LOG(INFO, "超时...\n");
            }
            else 
            {
                LOG(ERROR, "poll 出错...\n");
            }
        }
    }

    void PrintDebug()
    {
        std::cout << "fd: ";
        for(size_t i = 0; i < gnum; ++i)
        {
            if(_events[i].fd != -1)
            {
                std::cout << _events[i].fd << " ";
            }
        }
        std::cout << std::endl;
    }

private:
    std::unique_ptr<sock::TcpSocket> _sock; // 封装的 Tcp套接字的接口
    uint16_t _port;                         // 端口
    pollfd _events[gnum];                   // pollfd 数组
};